"""
人脸匹配模块
计算两个人脸特征之间的相似度
"""

import face_recognition
import numpy as np
from typing import List, Tuple, Dict, Any


def compare_faces(known_face_encodings,
                  unknown_face_encoding: np.ndarray,
                  tolerance: float = 0.6):
    """
    比较人脸特征
    :param known_face_encodings: 已知人脸特征列表
    :param unknown_face_encoding: 未知人脸特征
    :param tolerance: 匹配容差，越小越严格，默认值设为0.6
    :return: 匹配结果列表
    """
    try:
        # 确保unknown_face_encoding是numpy数组
        if not isinstance(unknown_face_encoding, np.ndarray):
            unknown_face_encoding = np.array(unknown_face_encoding)
        
        # 检查特征向量维度，face_recognition标准为128维
        if len(unknown_face_encoding.shape) != 1 or unknown_face_encoding.shape[0] != 128:
            print(f"警告: 未知人脸特征维度异常: {unknown_face_encoding.shape}")
            return []
        
        # 确保known_face_encodings是列表格式
        if isinstance(known_face_encodings, np.ndarray):
            known_face_encodings = known_face_encodings.tolist()
        
        # 过滤掉维度不匹配的已知人脸特征
        valid_known_encodings = []
        for encoding in known_face_encodings:
            if isinstance(encoding, np.ndarray) and len(encoding.shape) == 1 and encoding.shape[0] == 128:
                valid_known_encodings.append(encoding)
            elif isinstance(encoding, list) and len(encoding) == 128:
                valid_known_encodings.append(encoding)
        
        if not valid_known_encodings:
            print("警告: 没有有效的已知人脸特征")
            return []
        
        # 比较人脸特征
        matches = face_recognition.compare_faces(valid_known_encodings, unknown_face_encoding, tolerance)
        return matches.tolist() if isinstance(matches, np.ndarray) else matches
    except Exception as e:
        print(f"人脸比较失败: {e}")
        return []


def recognize_face(unknown_face_encoding: np.ndarray,
                   face_database: Dict[str, Any]) -> Tuple[str, float]:
    """
    识别人脸
    :param unknown_face_encoding: 未知人脸特征
    :param face_database: 人脸数据库 {name: encoding}
    :return: (匹配的人名, 相似度)
    """
    try:
        # 确保unknown_face_encoding是numpy数组
        if not isinstance(unknown_face_encoding, np.ndarray):
            unknown_face_encoding = np.array(unknown_face_encoding)
        
        # 检查特征向量维度
        if len(unknown_face_encoding.shape) != 1 or unknown_face_encoding.shape[0] != 128:
            print(f"警告: 未知人脸特征维度异常: {unknown_face_encoding.shape}")
            return "未知", 0.0
        
        # 过滤出有效的已知人脸特征和对应的名称
        valid_known_encodings = []
        valid_known_names = []
        
        for name, encoding in face_database.items():
            if isinstance(encoding, np.ndarray) and len(encoding.shape) == 1 and encoding.shape[0] == 128:
                valid_known_encodings.append(encoding)
                valid_known_names.append(name)
            elif isinstance(encoding, list) and len(encoding) == 128:
                valid_known_encodings.append(np.array(encoding))
                valid_known_names.append(name)
            elif isinstance(encoding, dict):
                # 兼容新的数据结构
                if "encodings" in encoding:
                    for face_info in encoding["encodings"]:
                        enc = face_info["encoding"]
                        if isinstance(enc, np.ndarray) and len(enc.shape) == 1 and enc.shape[0] == 128:
                            valid_known_encodings.append(enc)
                            valid_known_names.append(name)
                        elif isinstance(enc, list) and len(enc) == 128:
                            valid_known_encodings.append(np.array(enc))
                            valid_known_names.append(name)
                elif "encoding" in encoding:
                    enc = encoding["encoding"]
                    if isinstance(enc, np.ndarray) and len(enc.shape) == 1 and enc.shape[0] == 128:
                        valid_known_encodings.append(enc)
                        valid_known_names.append(name)
                    elif isinstance(enc, list) and len(enc) == 128:
                        valid_known_encodings.append(np.array(enc))
                        valid_known_names.append(name)
        
        # 检查是否有有效的已知人脸
        if not valid_known_encodings:
            print("警告: 没有有效的已知人脸特征")
            return "未知", 0.0
        
        # 转换为numpy数组
        valid_known_encodings = np.array(valid_known_encodings)
        
        # 计算距离
        face_distances = face_recognition.face_distance(valid_known_encodings, unknown_face_encoding)
        
        # 找到最佳匹配
        best_match_index = np.argmin(face_distances)
        best_distance = face_distances[best_match_index]
        
        # 计算相似度 (距离越小相似度越高)
        confidence = 1 - best_distance
        
        # 确保返回的是float类型
        confidence = float(confidence)
        
        # 检查是否匹配，使用更合适的阈值0.6
        # 将numpy数组转换为列表以避免类型错误
        encodings_list = valid_known_encodings.tolist() if isinstance(valid_known_encodings, np.ndarray) else valid_known_encodings
        matches = compare_faces(encodings_list, unknown_face_encoding, tolerance=0.6)
        if best_match_index < len(matches) and matches[best_match_index]:
            name = valid_known_names[best_match_index]
        else:
            name = "未知"
            
        return name, confidence
    except Exception as e:
        print(f"人脸识别失败: {e}")
        return "未知", 0.0


def recognize_face_advanced(unknown_face_encoding: np.ndarray,
                           face_database: Dict[str, Any]) -> Tuple[str, float]:
    """
    高级人脸识别，通过聚合一个人的所有人脸特征来提高识别准确率
    :param unknown_face_encoding: 未知人脸特征
    :param face_database: 人脸数据库 {name: {encodings: [{id, encoding, image_path}]}}
    :return: (匹配的人名, 相似度)
    """
    try:
        # 确保unknown_face_encoding是numpy数组
        if not isinstance(unknown_face_encoding, np.ndarray):
            unknown_face_encoding = np.array(unknown_face_encoding)
        
        # 检查特征向量维度
        if len(unknown_face_encoding.shape) != 1 or unknown_face_encoding.shape[0] != 128:
            print(f"警告: 未知人脸特征维度异常: {unknown_face_encoding.shape}")
            return "未知", 0.0
        
        # 检查是否有已知人脸
        if not face_database:
            return "未知", 0.0
        
        best_person = "未知"
        best_confidence = 0.0
        
        # 对数据库中的每个人计算平均相似度
        for name, person_data in face_database.items():
            person_encodings = []
            valid_encodings_count = 0
            
            if isinstance(person_data, dict) and "encodings" in person_data:
                # 新的数据结构：一个人对应多个人脸特征
                for face_info in person_data["encodings"]:
                    encoding = face_info["encoding"]
                    # 转换回numpy数组
                    if isinstance(encoding, list):
                        encoding = np.array(encoding)
                    # 检查维度是否有效
                    if isinstance(encoding, np.ndarray) and len(encoding.shape) == 1 and encoding.shape[0] == 128:
                        person_encodings.append(encoding)
                        valid_encodings_count += 1
                    else:
                        print(f"警告: 人员{name}的人脸特征维度异常: {encoding.shape if isinstance(encoding, np.ndarray) else type(encoding)}")
            else:
                # 兼容旧的数据结构
                encoding = None
                if isinstance(person_data, dict) and "encoding" in person_data:
                    encoding = person_data["encoding"]
                else:
                    # 最老的数据结构
                    encoding = person_data
                    
                # 转换并检查维度
                if isinstance(encoding, list):
                    encoding = np.array(encoding)
                if isinstance(encoding, np.ndarray) and len(encoding.shape) == 1 and encoding.shape[0] == 128:
                    person_encodings.append(encoding)
                    valid_encodings_count += 1
                else:
                    print(f"警告: 人员{name}的人脸特征维度异常: {encoding.shape if isinstance(encoding, np.ndarray) else type(encoding)}")
            
            if valid_encodings_count > 0 and len(person_encodings) > 0:
                # 计算未知人脸与该人员所有人脸特征的距离
                person_encodings = np.array(person_encodings)
                face_distances = face_recognition.face_distance(person_encodings, unknown_face_encoding)
                
                # 计算平均距离和最大相似度
                avg_distance = np.mean(face_distances)
                max_similarity = 1 - np.min(face_distances)  # 最佳匹配的相似度
                avg_similarity = 1 - avg_distance  # 平均相似度
                
                # 使用加权平均作为最终相似度（更重视最佳匹配）
                weighted_similarity = 0.7 * max_similarity + 0.3 * avg_similarity
                
                # 确保返回的是float类型
                weighted_similarity = float(weighted_similarity)
                
                # 更新最佳匹配
                if weighted_similarity > best_confidence:
                    best_confidence = weighted_similarity
                    best_person = name
        
        # 检查是否超过阈值
        best_confidence = float(best_confidence)
        if best_confidence >= 0.6:  # 可以根据需要调整这个阈值
            return best_person, best_confidence
        else:
            return "未知", best_confidence
            
    except Exception as e:
        print(f"高级人脸识别失败: {e}")
        return "未知", 0.0